PHP installed by default is similar to a regular package purchased in a department store, but it works well, but is not perfect. Tuning PHP is like tailored gear. However, it should be noted that tuning PHP is only a means to improve PHP performance and efficiency. It has nothing to do with bad code and unresponsive API calls.
php.ini file
The PHP interpreter is php.ini
configured and tuned in a file. The location of this file is different in different operating systems, and php.ini
the php.ini
file corresponding to the regular command line and the file corresponding to PHP-FPM are separated. Here, we assume that configuring PHP-FPM correspondsphp.ini
, but the optimization measures described below apply to all php.ini
.
Note: We should first scan the php.ini using the PHP Iniscan tool to check that security best practices are used.
RAM
When running PHP, you need to care about how much memory each PHP process will use php.ini
. The memory_limit
setting in is used to set the maximum system memory that a single PHP process can use.
The default value of this setting is 128M, which may work for most small and medium PHP applications. However, if you are running a micro PHP application, you can lower this value to save system resources. On the other hand, if you are running a memory-intensive PHP application, you can increase this value. The size of this value is determined by the available system memory, and determining how much value to allocate to PHP is an art.
When deciding how much memory to allocate to PHP, and how many PHP-FPM processes can be afforded, you can judge based on the following dimensional information:
-
How much memory can be allocated to PHP in total? Take a VPS with 2G memory as an example, there may be other processes running on this device, such as MySQL, Nginx, etc., then it is appropriate to leave 512M for PHP.
-
How much memory does each PHP process consume on average? To monitor the memory usage of the process, you can use command line commands
top
or call functions in PHP scriptsmemory_get_peak_usage()
. No matter which method is used, you must run the same script multiple times and then take the average memory consumption. -
How many PHP-FPM processes can I afford? Suppose I allocate 512M of memory to PHP, and each PHP process consumes an average of 15M of memory, then I can afford 34 PHP-FPM processes.
-
Do you have enough system resources? Finally, you need to confirm that you have sufficient system resources to run your PHP application and handle the expected traffic.
Note: We should use Apache Bench or Siege to stress test PHP applications under similar production environment conditions to determine if the production environment has sufficient resources available.
Zend OPcache
Once you have determined how much memory to allocate, you can configure PHP's Zend OPcache extension
This extension is built into PHP 5.5.0+. Here are the settings used to configure and optimize the Zend OPcache extension in the php.ini
file:
-
opcache.memory_consumption = 64
: The amount of memory allocated for the opcode cache (in MB). The amount of memory allocated should be able to store opcodes compiled by all PHP scripts in the application. This value can be set to different values depending on the size of the application. -
opcache.interned_strings_buffer = 16
: The amount of memory (in MB) used to store resident strings. What is a resident string? The PHP interpreter will then find multiple instances of the same string and save this string in memory. If you use the same string again, the PHP interpreter will use pointers to save memory. By default, PHP resident strings are isolated in every PHP process. This setting allows the PHP-FPM process pool to store all process-resident strings in a shared buffer so that it can be stored in the PHP-FPM process pool. Saving resident strings by referencing resident strings across multiple processes. -
opcache.max_accelerated_files = 4000
: The maximum number of PHP scripts that can be stored in the opcode cache. The value ranges from 2000 to 100,000. This value must be greater than the number of files in the PHP application. -
opcache.validate_timestamps = 1
: When the value of this setting is 1, after a period of time, PHP will check if the content of the PHP script has changed, and check that the interval is specified by theopcache.revalidate_freq
setting. If the value of this setting is 0, PHP will not check the contents of the PHP script for changes, and we must clear the cached opcodes ourselves. It is recommended to set it to 1 in the development environment and 0 in the production environment. -
opcache.revalidate_freq = 0
: Set how often (in seconds) to check whether the content of the PHP script has changed. The setting of 0 seconds means that only whenopcache.validate_timestamps
set to 1, PHP files are re-verified every time they are requested, so PHP files are re-verified every time in the development environment, not in the production environment. -
opcache.fast_shutdown = 1
: This setting allows opcodes to use faster downtime, leaving object destruction and memory release to Zend Engine's memory manager.
File Upload
If your application allows uploading files, it is best to set the maximum file size that can be uploaded. In addition, it is best to set how many files can be uploaded at one time:
file_uploads = 1
upload_max_filesize = 10M
max_file_uploads = 3
By default, PHP allows 20 files to be uploaded in a single request. The maximum uploaded file is 2MB. Here, I set it to upload up to 3 files in a single request, each file has a maximum size of 10MB. Do not set this value either. Large, otherwise timeouts will occur.
Note: If you have to upload large files, the configuration of the web server must be adjusted accordingly. In addition
php.ini
to the settings in, also adjust the settings in the Nginx virtual host configurationclient_max_body_size
.
Maximum execution time
php.ini
The file is max_execution_time
used to set the maximum time a single PHP process can run before terminating. This setting defaults to 30 seconds, and it is recommended to set it to 5 seconds:
max_execution_time = 5
Note: You can call the set_limit_time () function in a PHP script to override this setting.
Suppose we want to generate a report and generate the results as a PDF file. The task may take 10 minutes to complete, and we certainly don't want to wait for 10 minutes for PHP requests. We should write a separate PHP file and put it in a separate background. After executing in this process, the web application can generate a separate background process in milliseconds and then return an HTTP response:
<?php
exec('echo "create-report.php" | at now');
echo 'report pending...';
create-report.php
Runs in a separate background process. After running, you can update the database or email the report to the recipient. However, this usage is rare. Usually, we achieve similar functionality by using queues asynchronously. No matter in terms of security, scalability and maintainability, the effect is better. Related components include lightweight message queues such as PHPResque.
Handling sessions
PHP's default session handler slows down large applications because that handler stores session data on the hard disk, causing unnecessary disk I / O and wasting time. We should keep the session data in memory, for example using Memcached or Redis. This has an additional benefit-it will be easier to expand in the future. If session data is stored on a hard disk, it is inconvenient to add additional servers. If session data is stored in Memcached or Redis, any distributed PHP-FPM server can access session data.
If you want to save session data in Memcached, you need to do the following configuration:
session.save_handler = 'memcached'
session.save_path = '127.0.0.1:11211'
Buffered output
The network will be more efficient if more data is sent in fewer blocks, rather than less data in more blocks, meaning that the content is delivered for access in fewer fragment browsers, This can reduce the total number of HTTP requests.
Therefore, we must let PHP buffer the output. By default, PHP has output buffering enabled, and PHP will send content to the web server after buffering 4096 bytes of output.
output_buffering = 4096
implicit_flush = false
Note: If you want to modify the size of the output buffer, ensure that the value used is a multiple of 4 (32-bit system) or 8 (64-bit system) .
Real path cache
PHP caches the file paths used by the application, so that you do not need to constantly search for include paths each time you include or import a file. This cache is called the realpath cache. If you are running a large PHP file (such as a Composer component), With a large number of files, increasing the size of the PHP real path cache can get better performance.
The default size of the real path cache is 16K. The exact size required for this cache is not easy to determine, but some techniques can be used: First, increase the size of the actual path cache and set it to a particularly large value, such as 256K. Finally, add it at the end of the php script to print_r(realpath_cache_size());
output the real size of the real path cache. Finally, change the size of the real path cache to this real value. We can set the size of the real path cache in the php.ini
file:
realpath_cache_size = 64K
默認情況下安裝的PHP類似於在百貨商店中購買的常規軟件包,但它非常合適,但並不完美。調優的PHP就像是量身定制的裝備。但是,應該注意的是,調優PHP只是提高PHP性能和效率的一種手段,它與不良的代碼和無響應的API調用無關。
php.ini文件
PHP解釋器在 php.ini
文件中配置和調優,此文件的位置在不同的操作系統中是不同的,並且常規命令行對應 php.ini
和PHP-FPM對應的 php.ini
文件是分開的。在這裡,我們假設配置PHP-FPM 對應於php.ini
,但是下面講的優化措施適用於所有 php.ini
。
注:我們首先應該使用 PHP Iniscan 工具掃描php.ini,檢查使用了安全方面的最佳實踐。
內存
運行PHP時需要關心每個PHP進程要使用多少內存,php.ini
中的 memory_limit
設置用於設定單個PHP進程可以使用的系統內存最大值。
此設置的默認值為128M,這可能適用於大多數中小型PHP應用程序。但是,如果您正在運行微型PHP應用程序,則可以降低此值以節省系統資源。另一方面,如果您正在運行內存密集型的PHP應用程序,則可以增加該值。此值的大小由可用的系統內存確定,確定為PHP分配多少值是一門藝術。
決定給PHP 分配多少內存,以及能負擔起多少個PHP-FPM 進程時,可以根據以下維度信息進行判斷:
-
一共可以分配給PHP 多少內存?以一個2G 內存的VPS 為例,這台設備中可能還運行了其他進程,如MySQL、Nginx 等,那麼留512M 給PHP 是合適的。
-
每個PHP進程平均耗費多少內存?這個要監控進程的內存使用量,可以使用命令行命令
top
,也可以在PHP腳本中調用memory_get_peak_usage()
函數,不管使用哪種方式,都要多次運行同一個腳本,然後取內存消耗的平均值。 -
能負擔起多少個PHP-FPM 進程?假設我給PHP 分配了512M 內存,每個PHP 進程平均耗費15M 內存,那麼可以負擔起34 個PHP-FPM 進程。
-
有足夠的系統資源嗎?最後還需要確認有足夠的系統資源運行PHP 應用並處理預期的流量。
注:我們應該使用 Apache Bench 或 Siege 在類似生產環境的條件下對PHP應用做壓力測試,以確定生產環境是否有足夠的資源可用。
Zend OPcache
確定要分配多少內存後,就可以配置PHP 的Zend OPcache 擴展
PHP 5.5.0+內置了這個擴展,下面是在 php.ini
文件中配置和優化Zend OPcache擴展所用的設置:
-
opcache.memory_consumption = 64
:為操作碼緩存分配的內存量(以MB為單位)。分配的內存量應能夠存儲應用程序中所有PHP腳本編譯的操作碼。該值可以根據應用程序的大小設置為不同的值。 -
opcache.interned_strings_buffer = 16
:用於存儲常駐字符串的內存量(以MB為單位)。什麼是駐留字符串?PHP解釋器將在其後找到同一字符串的多個實例,並將此字符串保存在內存中。如果再次使用相同的字符串,PHP解釋器將使用指針,以節省內存。默認情況下,PHP駐留字符串在每個PHP進程中都是隔離的。此設置允許PHP-FPM進程池將所有進程駐留字符串存儲在共享緩衝區中,以便可以將其存儲在PHP-FPM進程池中。在多個進程之間引用常駐字符串,從而節省了更多內存。 -
opcache.max_accelerated_files = 4000
:可以存儲在操作碼緩存中的PHP腳本的最大數量。取值範圍是2000〜100,000。此值必須大於PHP應用程序中的文件數。 -
opcache.validate_timestamps = 1
:當此設置的值為1時,一段時間後,PHP將檢查PHP腳本的內容是否已更改,並檢查間隔由opcache.revalidate_freq
設置指定。如果此設置的值為0,則PHP將不會檢查PHP腳本的內容是否有更改,並且我們必須自己清除緩存的操作碼。建議在開發環境中將其設置為1,在生產環境中將其設置為0。 -
opcache.revalidate_freq = 0
:設置多久(單位是秒)檢查一次PHP腳本內容是否有變化。設置為0秒的含義是僅當opcache.validate_timestamps
設置為1時,每次請求PHP文件時都會重新驗證它們,因此,每次在開發環境中而不是在生產環境中都會重新驗證PHP文件。 -
opcache.fast_shutdown = 1
:此設置允許操作碼使用更快的停機時間,將對象破壞和內存釋放留給Zend Engine的內存管理器。
文件上傳
如果您的應用程序允許上傳文件,則最好設置可以上傳的最大文件大小。另外,最好設置一次可以上傳多少個文件:
file_uploads = 1
upload_max_filesize = 10M
max_file_uploads = 3
默認情況下,PHP允許在單個請求中上傳20個文件。上傳的最大文件為2MB。在這裡,我將其設置為在單個請求中最多上傳3個文件,每個文件的最大大小為10MB。也不要設置此值。很大,否則會發生超時。
注:如果非要上傳大文件,Web服務器的配置也要做相應調整。除了在
php.ini
中設置之外,還要調整Nginx虛擬主機配置中的client_max_body_size
設置。
最長執行時間
php.ini
文件中的 max_execution_time
用於設置單個PHP進程在終止之前可以運行的最長時間。此設置默認為30秒,建議將其設置為5秒:
max_execution_time = 5
注:在PHP 腳本中可以調用set_limit_time() 函數覆蓋這個設置。
假設我們要生成報告並將結果生成為PDF文件。該任務可能需要10分鐘才能完成,並且我們當然不希望等待PHP請求10分鐘。我們應該編寫一個單獨的PHP文件,並將其放在單獨的背景中。在該流程中執行後,Web應用程序可以在幾毫秒內生成一個單獨的後台流程,然後返回HTTP響應:
<?php
exec('echo "create-report.php" | at now');
echo 'report pending...';
create-report.php
在單獨的後台進程中運行。運行之後,您可以更新數據庫或將報告通過電子郵件發送給收件人。但是,這種用法很少見。通常,我們通過異步使用隊列來實現類似的功能。無論在安全性,可伸縮性和可維護性方面,效果都更好。相關組件具有輕量級消息隊列PHPResque等。
處理會話
PHP的默認會話處理程序減慢了大型應用程序的速度,因為該處理程序將會話數據存儲在硬盤上,從而造成不必要的磁盤I / O並浪費時間。我們應該將會話數據保留在內存中,例如使用Memcached或Redis。這還有一個額外的好處-將來更容易擴展。如果會話數據存儲在硬盤上,則添加其他服務器不方便。如果會話數據存儲在Memcached或Redis中,則任何分佈式PHP-FPM服務器都可以訪問會話數據。
如果想把會話數據保存在Memcached 中,需要做如下配置:
session.save_handler = 'memcached'
session.save_path = '127.0.0.1:11211'
緩衝輸出
如果在更少的塊中發送更多的數據,而不是在更多的塊中發送更少的數據,則網絡將更加高效,也就是說,以更少的片段瀏覽器傳遞內容以進行訪問,這可以減少HTTP請求的總數。
因此,我們必須讓PHP緩衝輸出。默認情況下,PHP已啟用輸出緩衝功能,並且PHP將在緩衝4096字節的輸出後將內容髮送到Web服務器。
output_buffering = 4096
implicit_flush = false
注:如果想要修改輸出緩衝區的大小,確保使用的值是4(32位系統)或8(64位系統)的倍數。
真實路徑緩存
PHP 會緩存應用使用的文件路徑,這樣每次包含或導入文件時就無需不斷搜索包含路徑了,這個緩存叫真實路徑緩存(realpath cache),如果運行的是大型的PHP 文件(如Composer 組件),使用了大量文件,增加PHP 真實路徑緩存的大小能得到更好的性能。
真實路徑緩存的默認大小為16K。此緩存所需的確切大小不易確定,但可以使用一些技巧:首先,增加實際路徑高速緩存的大小並將其設置為特別大的值,例如256K。最後在php腳本末尾添加上 print_r(realpath_cache_size());
,輸出真實路徑緩存的真正大小,最後,把真實路徑緩存的大小改為這個真正的值。我們可以在 php.ini
文件中設置真實路徑緩存的大小:
realpath_cache_size = 64K
Ref:https://mp.weixin.qq.com/s/hbDVX53mrsJt81OPovpdeg